#ifndef APRS3_H_
#define APRS3_H_

#include <apr.h>
#include <apr_uri.h>
#include <apr_strings.h>
#include <apr_atomic.h>
#include <apr_base64.h>
#include <apr_getopt.h>
#include <apr_version.h>
#include <apr_file_io.h>
#include <apr_file_info.h>

#include <libxml/parser.h>
#include <libxml/xpath.h>

#include "serf.h"

#include "aprs3_version.h"

#define S3_DEFAULT_NS "http://s3.amazonaws.com/doc/2006-03-01/"
#define S3_HOST_NAME  "s3.amazonaws.com"
#define S3_HTTP_PORT  80
#define S3_HTTPS_PORT 443

/** In APR 1.3 */
/** index into an apr_array_header_t */
#ifndef APR_ARRAY_IDX
#define APR_ARRAY_IDX(ary,i,type) (((type *)(ary)->elts)[i])
#endif

/** easier array-pushing syntax */
#ifndef APR_ARRAY_PUSH
#define APR_ARRAY_PUSH(ary,type) (*((type *)apr_array_push(ary)))
#endif

typedef enum {
    S3_REQUEST_UNSPEC,
    S3_LIST_BUCKETS,
    S3_LIST_FILES,
    S3_CREATE_BUCKET,
    S3_DELETE_BUCKET,
    S3_DELETE_OBJECT,
    S3_PUT,
    S3_GET,
} s3_request_e;

typedef enum {
    S3_SUCCESS,
    S3_ERROR
} s3_error_e;

typedef struct {
    const char *bucket;
    const char *prefix;
    const char *objkey;
    const char *output_filename;
} s3_data_t;

typedef struct {
#if APR_MAJOR_VERSION > 0
    apr_uint32_t requests_outstanding;
#else
    apr_atomic_t requests_outstanding;
#endif
    int using_ssl;
    const char *s3_key;
    const char *s3_id;
    serf_context_t *serf_ctx;
} s3_context_t;

typedef struct {
    apr_sockaddr_t *address;
    serf_connection_t *serf_conn;
    serf_ssl_context_t *ssl_ctx;
    serf_bucket_alloc_t *bkt_alloc;
    s3_context_t *ctx;
} s3_connection_t;

typedef struct s3_request_t s3_request_t;

typedef void (*response_cb)(struct s3_request_t *req);

struct s3_request_t {
    apr_time_t req_time;
    apr_pool_t *subpool;

    s3_error_e       err;
    s3_connection_t *acceptor_baton;
    s3_data_t       *s3_data;
    s3_request_e     type;

    serf_response_acceptor_t acceptor;
    serf_response_handler_t  handler;
    serf_request_t          *serf_request;

    const char *method;
    const char *path;
    const char *req_body_path;
    const char *authn;

    /* Response Data Handlers */
    xmlParserCtxtPtr xc; /**< libXML Parser */
    apr_file_t      *outfile;
};

s3_connection_t*
s3_connection_create(s3_context_t *ctx, apr_pool_t *pool);

s3_context_t* 
s3_context_create(const char *key, const char *id, int using_ssl, 
                  apr_pool_t *pool);

void 
s3_connection_close(s3_connection_t *conn);

apr_status_t 
s3_run(s3_context_t *ctx, apr_pool_t *pool);


s3_request_t* 
s3_create_request(s3_connection_t *conn, 
                  s3_request_e type, 
                  s3_data_t *s3_data, 
                  apr_pool_t *pool);
#endif
